package com.db.server.data;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import com.db.data.Order;
import com.db.protocol.tags.OrderSide;
import com.db.protocol.tags.OrderType;


public class OrderBook {
	
	private final String tickerSymbol;
	
	public String getTickerSymbol() {
		return tickerSymbol;
	}
	
	private List<ServerOrder> buyOrders;
	private List<ServerOrder> sellOrders;
	private List<ServerOrder> buyMarketOrders;
	private List<ServerOrder> sellMarketOrders;
	
	public OrderBook(String tickerSymbol) {
		this.tickerSymbol = tickerSymbol;
		buyOrders = new LinkedList<ServerOrder>();
		sellOrders = new LinkedList<ServerOrder>();
		buyMarketOrders = new LinkedList<ServerOrder>();
		sellMarketOrders = new LinkedList<ServerOrder>();		
	}

	public boolean hasOrder(String orderID) {
		for (Order order : buyOrders) {
			if (order.getOrderID().equals(orderID)) {
				return true;
			}
		}
		for (Order order : sellOrders) {
			if (order.getOrderID().equals(orderID)) {
				return true;
			}
		}
		for (Order order : buyMarketOrders) {
			if (order.getOrderID().equals(orderID)) {
				return true;
			}
		}
		for (Order order : sellMarketOrders) {
			if (order.getOrderID().equals(orderID)) {
				return true;
			}
		}
		return false;
	}
	
	public ServerOrder getOrder(String orderID) {
		for (ServerOrder order : buyOrders) {
			if (order.getOrderID().equals(orderID)) {
				return order;
			}
		}
		for (ServerOrder order : sellOrders) {
			if (order.getOrderID().equals(orderID)) {
				return order;
			}
		}
		for (ServerOrder order : buyMarketOrders) {
			if (order.getOrderID().equals(orderID)) {
				return order;
			}
		}
		for (ServerOrder order : sellMarketOrders) {
			if (order.getOrderID().equals(orderID)) {
				return order;
			}
		}
		return null;
	}
	
	public void add(ServerOrder order) {
		if  (order.getSide() == OrderSide.BUY) {
			if (order.getType() == OrderType.LIMIT) {
				addToBuy(order);
			} else {
				addToMarketBuy(order);
			}
		} else {
			if (order.getType() == OrderType.LIMIT) {
				addToSell(order);
			} else {
				addToMarketSell(order);
			}
		}
	}
	
	public void remove(Order order) {
		List<ServerOrder> list;
		if  (order.getSide() == OrderSide.BUY) {
			if (order.getType() == OrderType.LIMIT) {
				list = buyOrders;
			} else {
				list = buyMarketOrders;
			}
		} else {
			if (order.getType() == OrderType.LIMIT) {
				list = sellOrders;
			} else {
				list = sellMarketOrders;
			}
		}
		if (list != null) {
			synchronized (list) {
				list.remove(order);
			}
		}
	}
	
	private void addToBuy(ServerOrder order) {		
		synchronized (buyOrders) {
			int index = 0;
			Iterator<ServerOrder> iterator = buyOrders.iterator();
			while (iterator.hasNext() && iterator.next().compareTo(order) >= 0) {
				index++;
			}
			buyOrders.add(index, order);
		}
	}
	
	private void addToSell(ServerOrder order) {
		synchronized (sellOrders) {
			int index = 0;
			Iterator<ServerOrder> iterator = sellOrders.iterator();
			while (iterator.hasNext() && iterator.next().compareTo(order) <= 0) {
				index++;
			}
			sellOrders.add(index, order);
		}
	}

	private void addToMarketBuy(ServerOrder order) {
		synchronized (buyMarketOrders) {
			buyMarketOrders.add(order);
		}
	}
	
	private void addToMarketSell(ServerOrder order) {
		synchronized (sellMarketOrders) {
			sellMarketOrders.add(order);
		}
	}

	
	public ServerOrder bestBuyOrder() {
		if (buyOrders.isEmpty()) {
			return null;
		}
		return buyOrders.get(0);
	}

	public ServerOrder firstBuyMarketOrder() {
		if (buyMarketOrders.isEmpty()) {
			return null;
		}
		return buyMarketOrders.get(0);
	}

	public ServerOrder bestSellOrder() {
		if (sellOrders.isEmpty()) {
			return null;
		}
		return sellOrders.get(0);
	}

	public ServerOrder firstSellMarketOrder() {
		if (sellMarketOrders.isEmpty()) {
			return null;
		}
		return sellMarketOrders.get(0);
	}

	
	public boolean hasBuyOrder() {
		return !buyOrders.isEmpty();
	}

	public boolean hasBuyMarketOrder() {
		return !buyMarketOrders.isEmpty();
	}
	
	public boolean hasSellOrder() {
		return !sellOrders.isEmpty();
	}

	public boolean hasSellMarketOrder() {
		return !sellMarketOrders.isEmpty();
	}

}
